package com.winit.deploy.server;

import com.winit.common.util.ConfigUtil;
import com.winit.common.util.ObjectToString;
import com.winit.core.server.base.ExecResultHandler;
import com.winit.core.server.linux.LinuxJumpSSHServer;
import com.winit.deploy.bean.WinitTomcatInfo;
import com.winit.project.core.bean.PackageTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by wangjian on 16/8/15.
 */
public class WinitJumpServer extends LinuxJumpSSHServer {

    private static final Logger logger = LoggerFactory.getLogger(WinitJumpServer.class);

    private String serverIp;
    private Integer serverPort;
    private String level;//跳板机级别 1开始
    private String parentIp;//上级跳板机ip

    public WinitJumpServer(String ip, String userName, Integer port, String level, String parentIp) throws Exception {
        super(ip, userName, port);
        this.serverIp = ip;
        this.serverPort = port;
        this.level = level;
        this.parentIp = parentIp;
    }

    public String getIp() {
        return this.serverIp;
    }

    public Integer getServerPort() {
        return this.serverPort;
    }

    public boolean isConnected() {
        return this.session.isConnected();
    }

    /**
     * 向指定机器推送文件
     * 用于一级跳板机向二级跳板机推送文件
     *
     * @param fromPath 要推送文件的本地路径 文件
     * @param toPath   远程机器目标路径 目录
     * @param ip
     * @param sshPort
     * @throws Exception
     */
    public void doPush(String fromPath, String toPath, String ip, String sshPort) throws Exception {
        Assert.hasText(fromPath, "WinitJumpServer:执行推送,参数存在空值.fromPath");
        Assert.hasText(toPath, "WinitJumpServer:执行推送,参数存在空值.toPath");
        Assert.hasText(ip, "WinitJumpServer:执行推送,参数存在空值.ip");
        Assert.hasText(sshPort, "WinitJumpServer:执行推送,参数存在空值.sshPort");

        String keyFilePath = "/home/" + ConfigUtil.getValue("ssh_login_user") + "/" + ConfigUtil.getValue("ssh_key_file");
        String userName = ConfigUtil.getValue("ssh_login_user");

        StringBuffer cmd = new StringBuffer();
        cmd.append("scp -i ").append(keyFilePath).append(" -P ").append(sshPort)
                .append(" ").append(fromPath).append(" ").append(userName)
                .append("@").append(ip).append(":").append(toPath);
        ExecResultHandler handler = this.initHandler();
        this.doExec(handler, cmd.toString());
        logger.info("WinitJumpServer:执行推送,返回:" + handler.getMessage());
        if (!handler.isSuccess()) {
            //Warning: Permanently added '192.168.56.132' (ECDSA) to the list of known hosts.
            logger.error("WinitJumpServer:执行推送失败.返回:" + handler.getMessage());
            if (!handler.getMessage().startsWith("Warning:")) {
                throw new Exception("执行推送失败." + handler.getMessage());
            }
        }
    }

    public void mkdirs(String path) throws Exception {
        if (StringUtils.isEmpty(path)) {
            logger.error("WinitJumpServer:创建目录,参数存在空值." + path);
            throw new Exception("创建目录,参数存在空值");
        }
        ExecResultHandler handler = this.initHandler();
        this.doExec(handler, "mkdir -p " + path);
        logger.info("WinitJumpServer:创建目录" + path + ",返回:" + handler.getMessage());
        if (!handler.isSuccess()) {
            logger.error("WinitJumpServer:创建目录" + path + "失败,返回:" + handler.getMessage());
            throw new Exception("创建目录" + path + "失败." + handler.getMessage());
        }
    }

    public void deldirs(String path) throws Exception {
        if (StringUtils.isEmpty(path)) {
            logger.error("WinitJumpServer:删除目录,参数存在空值." + path);
            throw new Exception("删除目录不能为空");
        }
        Pattern pattern = Pattern.compile("^/*");
        Matcher matcher = pattern.matcher(path);
        boolean flag = matcher.matches();
        if (flag) {
            throw new Exception("不能删除根目录");
        }
        ExecResultHandler handler = this.initHandler();
        this.doExec(handler, "rm -rf " + path);
        logger.info("WinitJumpServer:删除目录" + path + ",返回:" + handler.getMessage());
        if (!handler.isSuccess()) {
            logger.error("WinitJumpServer:删除目录" + path + "失败,返回:" + handler.getMessage());
            throw new Exception("删除目录" + path + "失败." + handler.getMessage());
        }
    }

    //生成发布包
    public void createWarPackage(PackageTypeEnum typeEnum, String taskPath, String editionPath, String envName, String packageName
            , String nasNum, String projectConfigPath) throws Exception {
        Assert.hasText(taskPath, "WinitJumpServer:生成发布发布包,参数存在空值.taskPath");
        Assert.hasText(editionPath, "WinitJumpServer:生成发布发布包,参数存在空值.editionPath");
        Assert.hasText(envName, "WinitJumpServer:生成发布发布包,参数存在空值.envName");
        Assert.hasText(packageName, "WinitJumpServer:生成发布发布包,参数存在空值.packageName");
        switch (typeEnum) {
            case MAVEN_WAR:
                Assert.hasText(nasNum, "WinitJumpServer:生成发布发布包,参数存在空值.nasNum");
                break;
            case PHP:
                Assert.hasText(projectConfigPath, "WinitJumpServer:生成发布发布包,参数存在空值.projectConfigPath");
                break;
            default:
                break;
        }

        this.replaceConfigFile(typeEnum, taskPath, editionPath, envName, packageName, nasNum, projectConfigPath);
    }

    /**
     * 替换配置文件
     *
     * @param typeEnum
     * @param taskPath
     * @param editionPath
     * @param envName
     * @param packageName       发布包名
     * @param nasNum
     * @param projectConfigPath 工程内配置文件相对路径
     * @throws Exception
     */
    private void replaceConfigFile(PackageTypeEnum typeEnum, String taskPath, String editionPath, String envName
            , String packageName, String nasNum, String projectConfigPath) throws Exception {
        //1.解压发布临时目录下的配置文件包
        StringBuffer c = new StringBuffer();
        c.append("cd ").append(taskPath).append(" && rm -rf ").append(envName).append(" && tar -zxf ").append(envName).append(".tgz");
        ExecResultHandler handler = this.initHandler();
        this.doExec(handler, c.toString());
        if (!handler.isSuccess()) {
            logger.error("WinitJumpServer:替换配置文件失败,返回:" + handler.getMessage());
            throw new Exception("替换配置文件失败." + handler.getMessage());
        }
        //2.将配置文件替换进发布包
        StringBuffer cmd = new StringBuffer();

        switch (typeEnum) {
            case MAVEN_WAR:
                cmd.append("cd ").append(taskPath).append(" && rm -rf WEB-INF && cp -f ").append(editionPath).append("/target/").append(nasNum).append("/").append(packageName)
                        .append(".war ").append(packageName).append(".war && mkdir -p WEB-INF/classes/ && cp -Rf ").append(envName)
                        .append("/src/main/resources/* WEB-INF/classes/ && zip -m ").append(packageName).append(".war WEB-INF/classes/*");
                break;
            case PHP:
                String[] dir = projectConfigPath.split("/");
                cmd.append("source /etc/profile && cd ").append(taskPath).append(" && rm -rf ").append(dir[0])
                        .append(" && cp -f ").append(editionPath).append("/target/").append(packageName).append(".zip ").append(packageName).append(".zip").append(" && cp -Rf ")
                        .append(envName).append("/").append(dir[0]).append(" ").append(dir[0]).append(" && zip -m ").append(packageName).append(".zip ")
                        .append(projectConfigPath).append("/*");
                break;
            case SPRING_BOOT_JAR:
                cmd.append("cd ").append(taskPath).append(" && rm -rf ").append(packageName).append("* ").append(" && cp ").append(editionPath).append("/target/").append(packageName).append(".jar ").append(packageName).append(".jar  && cp -Rf ")
                        .append(envName).append("/src/main/resources/* ").append(taskPath).append("/ && rm -rf ").append(envName).append("* && tar -zcf ").append(packageName).append(".tgz * ");
                break;
            default:
                break;
        }

        handler = this.initHandler();
        this.doExec(handler, cmd.toString());
        if (!handler.isSuccess()) {
            logger.error("WinitJumpServer:替换配置文件失败,返回:" + handler.getMessage());
            throw new Exception("替换配置文件失败." + handler.getMessage());
        }
    }

    //替换jar包
    private void replaceJarFile(String taskPath, String warName
            , String replaceDir, String patchDir, String fileName, String prefix) throws Exception {
        //1.判断jar包是否存在
        this.isPathExist(patchDir + "/" + fileName);
        //2.将jar包替换到war包中
        StringBuffer cmd = new StringBuffer();
        cmd.append("cd ").append(taskPath).append(" && rm -rf WEB-INF && mkdir -p ").append(replaceDir)
                .append(" && cp -Rf ").append(patchDir).append("/").append(fileName).append(" ").append(replaceDir).append("/").append(fileName)
                .append(" && zip -d ").append(warName).append(".war /").append(replaceDir).append("/").append(prefix).append("* && zip -m ")
                .append(warName).append(".war ").append(replaceDir).append("/").append(fileName);
        ExecResultHandler handler = this.initHandler();
        this.doExec(handler, cmd.toString());
        if (!handler.isSuccess()) {
            logger.error("WinitJumpServer:替换jar包失败,返回:" + handler.getMessage());
            throw new Exception("替换jar包失败." + handler.getMessage());
        }
    }

    public void isPathExist(String path) throws Exception {
        if (StringUtils.isEmpty(path)) {
            logger.error("WinitJumpServer:判断路径是否存在,path为空.");
            throw new Exception("判断路径是否存在,path为空");
        }
        ExecResultHandler handler = this.initHandler();
        this.doExec(handler, "ls " + path);
        if (StringUtils.isEmpty(handler.getMessage())
                || handler.getMessage().indexOf("No such file or directory") != -1) {
            logger.error("WinitJumpServer:文件不存在.path=" + path);
            throw new Exception("文件不存在.path=" + path);
        }
    }

    public String getLevel() {
        return level;
    }

    public String getParentIp() {
        return parentIp;
    }

    private ExecResultHandler initHandler() {
        ExecResultHandler handler = new ExecResultHandler();
        return handler;
    }
}
